/**
 * <h3>Title wheel-utils系统</h3>
 * <h4>Description 工具包</h4>
 * <p>Company 心医国际数字医疗系统（大连） 有限公司</p>
 * <p>Copyright (c) 2019, Senyint. All rights reserved.</p>
 * @author WangNaiFei
 * @version 1.0 <i>2019年3月7日 下午6:55:43</i>
 */
package com.senyint.sys.utils.io;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;

import org.apache.commons.io.IOUtils;

/**
 * <dt>Description:</dt>
 * <dd>IO工具类</dd>
 * 
 * @author WangNaiFei,WangNaiFei@senyint.com
 * @version 1.0 <i>2017年1月8日 下午6:04:58</i>
 * @version 1.1 <i>2019年3月7日 下午10:42:02</i> 修改 流读取字符时出现乱码问题 改用 reader
 * @since jdk1.7+
 */
public class IOUtil extends IOUtils {

	/**
	 * <dt>Description:</dt>
	 * <dd>单线程 IO</dd>
	 * <dd>author WangNaiFei,WangNaiFei@senyint.com</dd>
	 * <dd>version 1.0 <i>2017年1月8日 下午6:05:51</i></dd>
	 * 
	 * @param inputStream 输入
	 * @param outputStream 输出
	 * @param offset 偏移
	 * @param contentlength 内容长度
	 * @param byteLenght 缓存长度
	 * @return true 成功 false 异常
	 */
	public static boolean outputTrad(InputStream inputStream, OutputStream outputStream, long offset, long contentlength, int byteLenght) {
		boolean raturn = false;
		if ((inputStream != null) && (outputStream != null)) {
			if (byteLenght <= 0)
				byteLenght = 4096; // 4k
			try {
				if (offset > 0L) {
					inputStream.skip(offset);
				}
				byte[] b = new byte[byteLenght];
				int len = 0;

				if (contentlength > 0L)
					while (contentlength > 0L) {
						if (contentlength < byteLenght)
							len = inputStream.read(b, 0, Integer.parseInt(String.valueOf(contentlength)));
						else {
							len = inputStream.read(b);
						}
						outputStream.write(b, 0, len);
						contentlength -= len;
					}
				else {
					while ((len = inputStream.read(b)) != -1) {
						outputStream.write(b, 0, len);
					}
				}
				raturn = true;
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				flushAndCloseQuietly(inputStream, outputStream);
			}

		}

		return raturn;
	}

	/**
	 * <dt>Description:</dt>
	 * <dd>生产者消费者IO</dd>
	 * <dd>author WangNaiFei,WangNaiFei@senyint.com</dd>
	 * <dd>version 1.0 <i>2017年1月8日 下午6:06:09</i></dd>
	 * 
	 * @param inputStream 输入
	 * @param outputStream 输出
	 * @param offset 偏移
	 * @param contentlength 内容长度
	 * @param byteLenght 缓存长度
	 * @return true 成功 false 异常
	 */
	public static boolean outputPC(InputStream inputStream, OutputStream outputStream, long offset, long contentlength, int byteLength) {
		boolean raturn = false;
		if ((inputStream != null) && (outputStream != null)) {
			if (byteLength <= 0) {
				byteLength = 4096; // 4k
			}
			PCIOStore store = new PCIOStore();// 总100*byteLength个字节缓存
			Thread tproducer = new Thread(new PCIOProducer(inputStream, store, offset, contentlength, byteLength));
			Thread tconsumer = new Thread(new PCIOConsumer(outputStream, store));

			tproducer.start();
			tconsumer.start();
			try {
				tproducer.join();
				tconsumer.join();
				raturn = true;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}

		return raturn;
	}

	/**
	 * <dt>Description:</dt>
	 * <dd>reader 转 String</dd>
	 * <dd>author WangNaiFei,WangNaiFei@senyint.com</dd>
	 * <dd>version 1.0 <i>2019年3月7日 下午10:57:03</i></dd>
	 * 
	 * @param reader
	 * @return
	 * @throws IOException
	 */
	public static String readerToString(Reader reader) throws IOException {
		return toString(reader);
	}

	/**
	 * <dt>Description:</dt>
	 * <dd>inputStream 转 String</dd>
	 * <dd>author WangNaiFei,WangNaiFei@senyint.com</dd>
	 * <dd>version 1.0 <i>2019年3月7日 下午10:55:18</i></dd>
	 * 
	 * @param inputStream
	 * @param charset
	 * @return
	 * @throws IOException
	 */
	public static String inputStreamToString(InputStream inputStream, String charset) throws IOException {
		return toString(inputStream, charset);
	}

	/**
	 * <dt>Description:</dt>
	 * <dd>inputStream 转 String UTF-8字符集</dd>
	 * <dd>author WangNaiFei,WangNaiFei@senyint.com</dd>
	 * <dd>version 1.0 <i>2019年3月7日 下午10:54:30</i></dd>
	 * 
	 * @param inputStream 输入流
	 * @return
	 * @throws IOException
	 */
	public static String inputStreamToString(InputStream inputStream) throws IOException {
		return inputStreamToString(inputStream, "utf-8");
	}

	/**
	 * <dt>Description:</dt>
	 * <dd>静默关闭</dd> <blockquote> 关闭{@code Closeable}<br>
	 * 关闭{@code Socket}<br>
	 * 关闭{@code ServerSocket}<br>
	 * </blockquote>
	 * <dd>author WangNaiFei,WangNaiFei@senyint.com</dd>
	 * <dd>version 1.0 <i>2017年3月5日 上午10:26:00</i></dd>
	 * 
	 * @see Flushable
	 * @param s 所有关闭对象
	 */
	public static void flushAndCloseQuietly(Object... s) {
		if (s != null) {
			for (Object o : s) {
				if (o instanceof Flushable) {
					flashQuietly((Flushable) o);
				}
				if (o instanceof Closeable) {
					closeQuietly((Closeable) o);
				} else if (o instanceof Collection) {
					for (Object obj : (Collection<?>) o) {
						flushAndCloseQuietly(obj);
					}
				} else if (o instanceof Socket) {
					try {
						((Socket) o).close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				} else if (o instanceof ServerSocket) {
					try {
						((ServerSocket) o).close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * <dt>Description:</dt>
	 * <dd>静默刷新</dd>
	 * <dd>author WangNaiFei,WangNaiFei@senyint.com</dd>
	 * <dd>version 1.0 <i>2017年4月7日 下午2:14:58</i></dd>
	 * 
	 * @param flushable 可刷新对象
	 */
	public static void flashQuietly(Flushable flushable) {
		if (flushable != null) {
			try {
				flushable.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * <dt>Description:</dt>
	 * <dd>inputStreanToByte</dd>
	 * <dd>author WangNaiFei,WangNaiFei@senyint.com</dd>
	 * <dd>version 1.0 <i>2019年3月7日 下午10:48:31</i></dd>
	 * 
	 * @param inStream
	 * @return byte
	 * @throws IOException
	 */
	public static final byte[] inputStreanToByte(InputStream inStream) throws IOException {
		ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
		int length = 4096;
		byte[] buff = new byte[length];
		int rc = 0;
		while ((rc = inStream.read(buff, 0, length)) > 0) {
			swapStream.write(buff, 0, rc);
		}
		byte[] in2b = swapStream.toByteArray();
		return in2b;
	}
}